<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  
  <title>【ThinkPHP5深入理解】控制器（三）-- 前置操作 | 程序小工  | Just do it!</title>
  <meta name="description" content="遇见更好的自己~" />
  <meta name="keywords" content="" />
  <meta name="HandheldFriendly" content="True" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <link rel="shortcut icon" href="/">
  <link rel="alternate" href="/atom.xml" title="程序小工  | Just do it!">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="[摘要]： tp5 框架的前置操作可以用于对某些方法进行通用的预处理，比如登录状态的判断[session 处理]、用户权限的卡控[cache/session 的处理]，通过控制器的前置操作，将公用代码进行封装，简化了调用流程[直接设定前置关系即可实现前置方法的自动调用]。">
<meta name="keywords" content="thinkphp5">
<meta property="og:type" content="article">
<meta property="og:title" content="【ThinkPHP5深入理解】控制器（三）-- 前置操作">
<meta property="og:url" content="http://blog.i2arch.tech/2018/08/07/tp5-controller3/index.html">
<meta property="og:site_name" content="程序小工  | Just do it!">
<meta property="og:description" content="[摘要]： tp5 框架的前置操作可以用于对某些方法进行通用的预处理，比如登录状态的判断[session 处理]、用户权限的卡控[cache/session 的处理]，通过控制器的前置操作，将公用代码进行封装，简化了调用流程[直接设定前置关系即可实现前置方法的自动调用]。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2018-08-14T07:59:24.564Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="【ThinkPHP5深入理解】控制器（三）-- 前置操作">
<meta name="twitter:description" content="[摘要]： tp5 框架的前置操作可以用于对某些方法进行通用的预处理，比如登录状态的判断[session 处理]、用户权限的卡控[cache/session 的处理]，通过控制器的前置操作，将公用代码进行封装，简化了调用流程[直接设定前置关系即可实现前置方法的自动调用]。">
    
  <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
  <link href='//cdn.bootcss.com/node-waves/0.7.5/waves.min.css' rel='stylesheet'>
  <link rel="stylesheet" href="/style.css">
  <script>
    function setLoadingBarProgress(num) {
      document.getElementById('loading-bar').style.width=num+"%";
    }
  </script>
</head>

<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script>
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				程序小工  | Just do it!
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-home' href='/'>
								<i class='icon icon-list2'></i>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								<i class='icon icon-bookmark'></i>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								<i class='icon icon-user'></i>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>

		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <!-- 左侧内容 -->
      <div class='l_main'>
        <article id="post-tp5-controller3"
  class="post white-box article-type-post"
  itemscope itemprop="blogPost">
	<section class='meta'>

	<h2 class="title">
  	<a href="/2018/08/07/tp5-controller3/">
    	【ThinkPHP5深入理解】控制器（三）-- 前置操作
    </a>
	</h2>

	<div class="pagenav">
		<time>
			2018-08-07
		</time>

		
    
    <div class='cats'>
        <i class="icon icon-bookmark"></i>
        <a href="/categories/PHP/">PHP</a>
    </div>


		
			<div class="pagetags">
				<i class="icon icon-price-tag" style="margin-right: 2px;"></i>
				
					<a href="/tags/thinkphp5/" style="margin-left: 3px;">
						thinkphp5
					</a>
				
			</div>
			
	</div>
	</section>

	
	<section class="toc-wrapper"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#一-基本用法"><span class="toc-text"> 一、基本用法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1使用示例"><span class="toc-text"> 1.使用示例：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2使用说明"><span class="toc-text"> 2.使用说明：</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二-使用介绍"><span class="toc-text"> 二、使用介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1控制器类属性-beforeactionlist"><span class="toc-text"> 1.控制器类属性: $beforeActionList</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2属性值-键值对"><span class="toc-text"> 2.属性值： 键值对</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3注意点"><span class="toc-text"> 3.【注意点】：</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二-实现原理源码阅读"><span class="toc-text"> 二、实现原理[源码阅读]</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1框架类库"><span class="toc-text"> 1.框架类库</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2相关介绍"><span class="toc-text"> 2.相关介绍</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3实现方法beforeaction"><span class="toc-text"> 3.实现方法：beforeAction()</span></a></li></ol></li></ol></section>
	

	<section class="article typo">
		<div class="article-entry" itemprop="articleBody">
				<span class="zhaiyao">[摘要]</span>
			<p>[摘要]：</p>
<p>tp5 框架的前置操作可以用于对某些方法进行通用的预处理，比如登录状态的判断[session 处理]、用户权限的卡控[cache/session 的处理]，通过控制器的前置操作，将公用代码进行封装，简化了调用流程[直接设定前置关系即可实现前置方法的自动调用]。</p>
<a id="more"></a>
<h2 id="一-基本用法"><a class="markdownIt-Anchor" href="#一-基本用法"></a> 一、基本用法</h2>
<h3 id="1使用示例"><a class="markdownIt-Anchor" href="#1使用示例"></a> 1.使用示例：</h3>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> $beforeActionList = [</span><br><span class="line"></span><br><span class="line">    <span class="string">'userBeforeAction1'</span> =&gt; [<span class="string">'only'</span> =&gt; <span class="string">'function1NeedDoBeforeAction1, function2DoNeedBeforeAction1'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="string">'userBeforeAction2'</span> =&gt; [<span class="string">'except'</span> =&gt; <span class="string">'function1NotNeedBeforeAction2, function2NotNeedBeforeAction2'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="string">'userBeforeAction3'</span></span><br><span class="line">];</span><br></pre></td></tr></table></figure>
<h3 id="2使用说明"><a class="markdownIt-Anchor" href="#2使用说明"></a> 2.使用说明：</h3>
<p>(1) <code>only</code> =&gt; 当调用 api 接口方法<code>function1NeedDoBeforeAction1()</code>和<code>function1NeedDoBeforeAction1</code>时，都会自动调用不公开[<code>protected</code>]的前置方法<code>userBeforeAction1()</code>，并且该前置方法只在访问这两个 api 方法时执行。</p>
<p>(2) <code>except</code> =&gt; api 接口方法<code>function1NotNeedBeforeAction2()</code>和<code>function1NotNeedBeforeAction2()</code>时，不会执行前置方法<code>userBeforeAction2()</code></p>
<h2 id="二-使用介绍"><a class="markdownIt-Anchor" href="#二-使用介绍"></a> 二、使用介绍</h2>
<blockquote>
<p>可以为某个或者某些操作指定前置执行的操作方法，设置 beforeActionList 属性可以指定某个方法为其他方法的前置操作，数组键名为需要调用的前置方法名，无值的话为当前控制器下所有方法的前置方法。</p>
</blockquote>
<h3 id="1控制器类属性-beforeactionlist"><a class="markdownIt-Anchor" href="#1控制器类属性-beforeactionlist"></a> 1.控制器类属性: $beforeActionList</h3>
<h3 id="2属性值-键值对"><a class="markdownIt-Anchor" href="#2属性值-键值对"></a> 2.属性值： 键值对</h3>
<ul>
<li>
<p>键：前置方法名</p>
</li>
<li>
<p>值：前置方法作用域[键值对|无]</p>
<ul>
<li>
<p>无值时： 对当前控制器所有 api 方法都执行前置</p>
</li>
<li>
<p>有值[键值对]：</p>
<ul>
<li>键：
<ul>
<li>except：除某些 api 方法执行前置</li>
<li>only：只对某些 api 方法执行前置</li>
</ul>
</li>
<li>值：需要进行前置操作的 api 方法 [当该项值为多个时，用半角,进行间隔]</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="3注意点"><a class="markdownIt-Anchor" href="#3注意点"></a> 3.【注意点】：</h3>
<p>（1）由于 TP5 框架对 url 的处理是全部转化为小写，并且执行前置操作时，也是通过 url 中参数获取当前调用的 api 方法，并判断是否需要进行前置操作的，所以定义需要执行前置方法的 api 方法时，都需要使用小写[针对 TP5.0 版本]</p>
<p>（2）前置方法的访问方式为<code>private</code>时，则无法调用。</p>
<h2 id="二-实现原理源码阅读"><a class="markdownIt-Anchor" href="#二-实现原理源码阅读"></a> 二、实现原理[源码阅读]</h2>
<h3 id="1框架类库"><a class="markdownIt-Anchor" href="#1框架类库"></a> 1.框架类库</h3>
<p>基类控制器<code>thinkphp\library\think\Controller.php</code></p>
<h3 id="2相关介绍"><a class="markdownIt-Anchor" href="#2相关介绍"></a> 2.相关介绍</h3>
<p>(1) 属性名：<code>$beforeActionList</code></p>
<p>前置方法列表：</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> $beforeActionList = [];</span><br></pre></td></tr></table></figure>
<p>(2) 构造方法：<code>__construc()</code></p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 遍历前置方法列表，并对每个前置方法进行前置处理</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">$this</span>-&gt;beforeActionList) &#123;</span><br><span class="line">    <span class="keyword">foreach</span> (<span class="keyword">$this</span>-&gt;beforeActionList <span class="keyword">as</span> $method =&gt; $options) &#123;</span><br><span class="line">        is_numeric($method) ?</span><br><span class="line">        <span class="keyword">$this</span>-&gt;beforeAction($options) :</span><br><span class="line">        <span class="keyword">$this</span>-&gt;beforeAction($method, $options);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>【逻辑分析】：</p>
<ul>
<li>
<p>判断前置数组的键是否为数值</p>
</li>
<li>
<p>如果是数值，直接对前置方法键值对的值进行处理</p>
</li>
<li>
<p>如果不是数值，则对每组前置关系进行处理</p>
</li>
</ul>
<h3 id="3实现方法beforeaction"><a class="markdownIt-Anchor" href="#3实现方法beforeaction"></a> 3.实现方法：<code>beforeAction()</code></h3>
<p>(1) 当<strong>前置方法</strong>[每组前置关系的键]是数值时 【键为数值的情况即 <strong>该组前置关系</strong> 没有指定前置方法的作用域，是对所有方法执行该前置方法】</p>
<ul>
<li>
<p>调用 – <code>$this-&gt;beforeAction($options)</code></p>
</li>
<li>
<p>实际执行过程为</p>
</li>
</ul>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">beforeAction</span><span class="params">($options)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    call_user_func([<span class="keyword">$this</span>, $options]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>(2) 当<strong>前置方法</strong>[每组前置关系的键]不是数值时</p>
<ul>
<li>
<p>调用 – <code>$this-&gt;beforeAction($method, $options)</code></p>
</li>
<li>
<p>完整执行过程为</p>
</li>
</ul>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">beforeAction</span><span class="params">($method, $options = [])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">isset</span>($options[<span class="string">'only'</span>])) &#123;</span><br><span class="line">        <span class="keyword">if</span> (is_string($options[<span class="string">'only'</span>])) &#123;</span><br><span class="line">            $options[<span class="string">'only'</span>] = explode(<span class="string">','</span>, $options[<span class="string">'only'</span>]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!in_array(<span class="keyword">$this</span>-&gt;request-&gt;action(), $options[<span class="string">'only'</span>])) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">elseif</span> (<span class="keyword">isset</span>($options[<span class="string">'except'</span>])) &#123;</span><br><span class="line">        <span class="keyword">if</span> (is_string($options[<span class="string">'except'</span>])) &#123;</span><br><span class="line">            $options[<span class="string">'except'</span>] = explode(<span class="string">','</span>, $options[<span class="string">'except'</span>]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (in_array(<span class="keyword">$this</span>-&gt;request-&gt;action(), $options[<span class="string">'except'</span>])) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    call_user_func([<span class="keyword">$this</span>, $method]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>（3）函数 [<a href="http://php.net/manual/en/function.call-user-func.php" target="_blank" rel="noopener">call_user_func</a>]功能：把第一个参数作为回调函数调用</p>
<ul>
<li>
<p>参数说明：</p>
<p>当传入的参数为一个数组时，则将数组的</p>
<ul>
<li>第一个元素作为 <strong>类名</strong> 或 <strong>类的实例化对象</strong></li>
<li>第二个元素作为类的方法名 [一般方法和静态方法均可以]</li>
</ul>
</li>
<li>
<p>调用结果：</p>
<p>就是直接执行该类下的相应方法的结果</p>
</li>
</ul>
<p>[全程学习+笔记时长：100min]</p>

		</div>

		
			<div class="art-item-footer">
					
						<span class="art-item-left"><i class="icon icon-chevron-thin-left"></i> <a href="/2018/08/08/js-react/" rel="prev" title="【React入门】实现todolist功能">
							【React入门】实现todolist功能
						</a>上一篇文章</span>
					
					
						<span class="art-item-right">下一篇文章：<a href="/2018/07/31/docker-base/" rel="next"  title="【Docker】--入门使用">
							【Docker】--入门使用
						</a><i class="icon icon-chevron-thin-right"></i></span>
					
			</div>
		

		
			

    <div class="recommended_posts">
        <h3>推荐文章</h3>
        <ul>
            
                <li><a href="http://blog.i2arch.tech/2018/08/13/git-modify-commit-message/">【Git】修改已经提交的commit内容</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/08/08/js-react/">【React入门】实现todolist功能</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/07/31/docker-base/">【Docker】--入门使用</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/07/31/docker-install/">【Docker】--安装与配置</a></li>
            
        </ul>
    </div>


		
	</section>

	

</article>
<script>
	window.subData = {
		title: '【ThinkPHP5深入理解】控制器（三）-- 前置操作',
		tools: true
	}
</script>

      </div>

      <!-- 右侧边栏组件 -->
      <aside class='l_side'>
        
      </aside>

      <div class="gotop">
          
    <a href='javascript:void(0)'>
        <i class="icon icon-arrow_upward flat-box">
        </i>
    </a>

      </div>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/zqunor" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://www.cnblogs.com/zqunor" class="social zhihu"
          target="_blank" rel="external">
          <span class="icon icon-zhihu"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a>  Powered by<a href="https://blog.i2arch.tech/" target="_blank">程序小工</a>.</div>

</footer>

  <script>setLoadingBarProgress(80);</script>
  

    <script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
    <script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
    <script src="/js/jquery.fitvids.js"></script>
      <script>
        var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
        var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
        var ALGOLIA_API_KEY = "";
        var ALGOLIA_APP_ID = "";
        var ALGOLIA_INDEX_NAME = "";
        var AZURE_SERVICE_NAME = "";
        var AZURE_INDEX_NAME = "";
        var AZURE_QUERY_KEY = "";
        var BAIDU_API_ID = "fca5b83cf69f752ddc96a61ef64a3659";
        var SEARCH_SERVICE = "hexo";
        var ROOT = "/" || "/";
        if (!ROOT.endsWith('/')) ROOT += '/';
      </script>
      <script src="/js/search.js"></script>
        <script src="/js/app.js"></script>
  <script>setLoadingBarProgress(100);</script>
</body>
</html>
